home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 3: Developer Tools / Linux Cubed Series 3 - Developer Tools.iso / utils / disk-man / mtools-3.000 / mtools-3 / mtools-3.0 / plain_io.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-05-12  |  6.1 KB  |  311 lines

  1. /*
  2.  * Io to a plain file or device
  3.  *
  4.  * written by:
  5.  *
  6.  * Alain L. Knaff            
  7.  * Alain.Knaff@inrialpes.fr
  8.  *
  9.  */
  10.  
  11. #include "sysincludes.h"
  12. #include "stream.h"
  13. #include "mtools.h"
  14. #include "msdos.h"
  15. #include "plain_io.h"
  16. #include "patchlevel.h"
  17.  
  18. typedef struct SimpleFloppy_t {
  19.     Class_t *Class;
  20.     int refs;
  21.     Stream_t *Next;
  22.     Stream_t *Buffer;
  23.     struct stat stat;
  24.     int fd;
  25.     int offset;
  26.     int lastwhere;
  27.     int seekable;
  28. } SimpleFloppy_t;
  29.  
  30.  
  31. /*
  32.  * Create an advisory lock on the device to prevent concurrent writes.
  33.  * Uses either lockf, flock, or fcntl locking methods.  See the Makefile
  34.  * and the Configure files for how to specify the proper method.
  35.  */
  36.  
  37. int lock_dev(int fd)
  38. {
  39. #if (defined(HAVE_LOCKF) && defined(F_TLOCK))
  40.     if (lockf(fd, F_TLOCK, 0) < 0)
  41. #else /* LOCKF */
  42.  
  43. #if (defined(HAVE_FLOCK) && defined (LOCK_EX) && defined(LOCK_NB))
  44.     if (flock(fd, LOCK_EX|LOCK_NB) < 0)
  45. #else /* FLOCK */
  46.  
  47. #if (defined(F_SETLK) && defined(F_WRLCK))
  48.     struct flock flk;
  49.  
  50.     flk.l_type = F_WRLCK;
  51.     flk.l_whence = 0;
  52.     flk.l_start = 0L;
  53.     flk.l_len = 0L;
  54.  
  55.     if (fcntl(fd, F_SETLK, &flk) < 0)
  56. #endif /* FCNTL */
  57. #endif /* FLOCK */
  58. #endif /* LOCKF */
  59.     {
  60.         if(errno == EINVAL)
  61.             return 0;
  62.         else
  63.             return 1;
  64.     }
  65.     return 0;
  66. }
  67.  
  68. typedef int (*iofn) (int, char *, int);
  69.  
  70. static int f_io(Stream_t *Stream, char *buf, int where, int len,
  71.         iofn io)
  72. {
  73.     DeclareThis(SimpleFloppy_t);
  74.     int ret;
  75.  
  76.     where += This->offset;
  77.     if (This->seekable && where != This->lastwhere ){
  78.         if(lseek( This->fd, where, SEEK_SET) < 0 ){
  79.             perror("seek");
  80.             This->lastwhere = -1;
  81.             return -1;
  82.         }
  83.     }
  84.     ret = io(This->fd, buf, len);
  85.     if ( ret == -1 ){
  86.         perror("read");
  87.         This->lastwhere = -1;
  88.         return -1;
  89.     }
  90.     This->lastwhere = where + ret;
  91.     return ret;
  92. }
  93.     
  94.  
  95.  
  96. static int f_read(Stream_t *Stream, char *buf, int where, int len)
  97. {    
  98.     return f_io(Stream, buf, where, len, (iofn) read);
  99. }
  100.  
  101. static int f_write(Stream_t *Stream, char *buf, int where, int len)
  102. {
  103.     return f_io(Stream, buf, where, len, (iofn) write);
  104. }
  105.  
  106. static int f_flush(Stream_t *Stream)
  107. {
  108. #if 0
  109.     DeclareThis(SimpleFloppy_t);
  110.  
  111.     return fsync(This->fd);
  112. #endif
  113.     return 0;
  114. }
  115.  
  116. static int f_free(Stream_t *Stream)
  117. {
  118.     DeclareThis(SimpleFloppy_t);
  119.  
  120.     if (This->fd > 2)
  121.         return close(This->fd);
  122.     else
  123.         return 0;
  124. }
  125.  
  126. #if 0
  127. int check_parameters(struct device *ref, struct device *testee)
  128. {
  129.     return 0;
  130. }
  131. #endif
  132.  
  133. static int f_geom(Stream_t *Stream, struct device *dev, 
  134.           struct device *orig_dev,
  135.           int media, struct bootsector *boot)
  136. {
  137.     int ret;
  138.     DeclareThis(SimpleFloppy_t);
  139.     unsigned long tot_sectors;
  140.     int BootP, Infp0, InfpX, InfTm;
  141.     int sectors, j;
  142.     unsigned char sum;
  143.     int sect_per_track;
  144.  
  145.     dev->ssize = 2; /* allow for init_geom to change it */
  146.     dev->use_2m = 0x80; /* disable 2m mode to begin */
  147.  
  148.     if(media == 0xf0 || media >= 0x100){        
  149.         dev->heads = WORD(nheads);
  150.         dev->sectors = WORD(nsect);
  151.         tot_sectors = DWORD(bigsect);
  152.         set_ulong(&tot_sectors, WORD(psect));
  153.         sect_per_track = dev->heads * dev->sectors;
  154.         tot_sectors += sect_per_track - 1; /* round size up */
  155.         dev->tracks = tot_sectors / sect_per_track;
  156.  
  157.         BootP = WORD(BootP);
  158.         Infp0 = WORD(Infp0);
  159.         InfpX = WORD(InfpX);
  160.         InfTm = WORD(InfTm);
  161.         
  162.         if (boot->descr >= 0xf0 &&
  163.             boot->dos4 == 0x29 &&
  164.             strncmp( boot->banner,"2M", 2 ) == 0 &&
  165.             BootP < 512 && Infp0 < 512 && InfpX < 512 && InfTm < 512 &&
  166.             BootP >= InfTm + 2 && InfTm >= InfpX && InfpX >= Infp0 && 
  167.             Infp0 >= 76 ){
  168.             for (sum=0, j=63; j < BootP; j++) 
  169.                 sum += boot->jump[j];/* checksum */
  170.             dev->ssize = boot->jump[InfTm];
  171.             if (!sum && 
  172.                 dev->ssize >= 0 && dev->ssize <= 7 ){
  173.                 dev->use_2m = 0xff;
  174.                 dev->ssize |= 0x80; /* is set */
  175.             }
  176.         }
  177.     } else if (media >= 0xf8){
  178.         media &= 3;
  179.         dev->heads = old_dos[media].heads;
  180.         dev->tracks = old_dos[media].tracks;
  181.         dev->sectors = old_dos[media].sectors;
  182.         dev->ssize = 0x80;
  183.         dev->use_2m = ~1;
  184.     } else {
  185.         fprintf(stderr,"Unknown media type\n");
  186.         cleanup_and_exit(1);
  187.     }
  188.  
  189.     sectors = dev->sectors;
  190.     dev->sectors = dev->sectors * WORD(secsiz) / 512;
  191.  
  192.     ret = init_geom(This->fd,dev, orig_dev, &This->stat);
  193.     dev->sectors = sectors;
  194.     return ret;
  195. }
  196.  
  197.  
  198. static int f_data(Stream_t *Stream, long *date, unsigned long *size,
  199.           int *type, int *address)
  200. {
  201.     DeclareThis(SimpleFloppy_t);
  202.  
  203.     if(date)
  204.         *date = This->stat.st_mtime;
  205.     if(size)
  206.         *size = This->stat.st_size;
  207.     if(type)
  208.         *type = S_ISDIR(This->stat.st_mode);
  209.     if(address)
  210.         *address = 0;
  211.     return 0;
  212. }
  213.  
  214. static Class_t SimpleFloppyClass = {
  215.     f_read, 
  216.     f_write,
  217.     f_flush,
  218.     f_free,
  219.     f_geom,
  220.     f_data
  221. };
  222.  
  223. Stream_t *SimpleFloppyOpen(struct device *dev, struct device *orig_dev,
  224.                char *name, int mode, char *errmsg)
  225. {
  226.     SimpleFloppy_t *This;
  227.  
  228.     This = New(SimpleFloppy_t);
  229.     if (!This){
  230.         fprintf(stderr,"Out of memory error\n");
  231.         cleanup_and_exit(1);
  232.     }
  233.     This->seekable = 1;
  234.  
  235.     This->Class = &SimpleFloppyClass;
  236.     if (strcmp(name,"-") == 0 ){
  237.         if (mode == O_RDONLY)
  238.             This->fd = 0;
  239.         else
  240.             This->fd = 1;
  241.         This->seekable = 0;
  242.         This->refs = 1;
  243.         This->Next = 0;
  244.         This->Buffer = 0;
  245.         return (Stream_t *) This;
  246.     }
  247.     
  248.     if(dev)
  249.         mode |= dev->mode;
  250.  
  251.     This->fd = open(name, mode, 0666);
  252.  
  253.     if (This->fd < 0) {        
  254.         Free(This);
  255.         if(errmsg)
  256.             sprintf(errmsg, "Can't open %s: %s",
  257.                 name, strerror(errno));
  258.         return NULL;
  259.     }
  260.  
  261.     if (fstat(This->fd, &This->stat) < 0){
  262.         Free(This);
  263.         if(errmsg)
  264.             sprintf(errmsg,"Can't stat %s: %s", 
  265.                 name, strerror(errno));
  266.  
  267.         return NULL;
  268.     }
  269.  
  270.     /* lock the device on writes */
  271.     if (mode == O_RDWR && lock_dev(This->fd)) {
  272.         close(This->fd);
  273.         Free(This);
  274.         if(errmsg)
  275.             sprintf(errmsg,
  276.                 "plain floppy: device \"%s\"busy\n:", 
  277.                 dev->name);
  278.         return NULL;
  279.     }
  280.         
  281.     /* set default parameters, if needed */
  282.     if (dev){
  283.         if (init_geom(This->fd, dev, orig_dev, &This->stat)){
  284.             close(This->fd);
  285.             Free(This);
  286.             if(errmsg)
  287.                 sprintf(errmsg,"init: set default params");
  288.             return NULL;
  289.         }
  290.         This->offset = dev->offset;
  291.     } else
  292.         This->offset = 0;
  293.  
  294.     This->refs = 1;
  295.     This->Next = 0;
  296.     This->Buffer = 0;
  297.  
  298.     /* partitioned drive */
  299.     while(dev && dev->partition && dev->partition <= 4) {
  300.         unsigned char ptable[512];
  301.         /* read the first sector, or part of it */
  302.         if (force_read((Stream_t *)This, (char*) ptable, 0, 512) != 512)
  303.             break;
  304.         if( _WORD(ptable+510) != 0xaa55)
  305.             break;
  306.         This->offset += (_DWORD(ptable+0x1a6+(dev->partition<<5))) << 9;
  307.         break;
  308.     }
  309.     return (Stream_t *) This;
  310. }
  311.